/* Name: AsteroidField
 * Author: Cameron Hoerig
 * Date: 5-5-12
 * Description: The AsteroidField class creates and draws an AsteroidField on screen. Players can create 
 *  wormholes to AsteroidField fields, but not through them.
 * Revisions: See Subversion logs at http://code.google.com/p/software-engineering-2012/source/list
 */

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import java.util.Iterator;
import java.util.LinkedList;

public class AsteroidField extends Item {
	private static LinkedList<AsteroidField> idList = new LinkedList<AsteroidField>();
	private Sprite sprite;
	private int numSprites;
	private int spriteDisOffset[];
	private float spriteDirOffset[];
	private float spriteDelDir[];
	private float spriteScales[];
	private float spriteRots[];
	private float spriteRotSpeed[];
	public float orePushRate = 0;
	private LinkedList<Wormhole> whList = new LinkedList<Wormhole>();
	
	// Places the AsteroidField randomly in the room, preventing collisions and impossible scenarios. Initializes graphics.
	public AsteroidField(int px, int py) {
		Game.create((Item)this, 15); // Needed for update, draw, and destroy
		colType = COL_CIRCLE; // Needed for collision checking
		idList.add(this); // Needed for collision checking
		sprite = Sprite.load("/sprites/Asteroid/asteroid.png");
		if (px == -1) {
			int attempt = 0;
			do {
				r = Game.randomInt(120, 150)*2;
				x = Game.randomInt(r,GameScreen.getWidth()-r);
				y = Game.randomInt(r,GameScreen.getHeight()-r);
			} while (Planet.checkCollision(this, false)!=0 || Nebula.checkCollision(this, false)!=0 || 
					AsteroidField.checkCollision(this, false)!=0 || Antimatter.checkCollision(this, false)!=0 ||
					Wormhole.checkCollision(this, false) != 0 || !GameScreen.isGameWinnable() || ++attempt >= 30);
			if (attempt >= 30) {
				GameScreen.throwRoomCreationError();
			}
		} else {
			r = Game.randomInt(120, 150)*2;
			x = px;
			y = py;
		}
		r /= 2;
		
		numSprites = Game.randomInt(15, 25);
		spriteDisOffset = new int[numSprites];
		spriteDirOffset = new float[numSprites];
		spriteDelDir = new float[numSprites];
		spriteScales = new float[numSprites];
		spriteRots = new float[numSprites];
		spriteRotSpeed = new float[numSprites];
		
		orePushRate = Game.randomFloat(.2f,.35f);
		Boolean rotateLeft = (Game.randomInt(2) == 0);
		for(int count=0; count<numSprites; count++){
			spriteDisOffset[count] = Game.randomInt(10+(sprite.getWidth()/2),r-(sprite.getWidth()/2));
			spriteDirOffset[count] = Game.randomFloat((float) (2.0f*Math.PI));
			if (rotateLeft) {
				spriteDelDir[count] = (0.1f/r)*Game.randomFloat(0.5f, 1.5f);
			} else {
				spriteDelDir[count] = (-0.1f/r)*Game.randomFloat(0.5f, 1.5f);
			}
			spriteScales[count] = Game.randomFloat(0.5f,1.0f);
			spriteRots[count] = Game.randomFloat(0.0f,(float) (2.0f*Math.PI));
			if (Game.randomInt(2) == 0) {
				spriteRotSpeed[count] = (float) (Game.randomFloat((float) (2.0f*Math.PI/10000.0f), (float) (2.0f*Math.PI/5000.0f)));
			} else {
				spriteRotSpeed[count] = (float) (Game.randomFloat((float) (-2.0f*Math.PI/5000.0f), (float) (-2.0f*Math.PI/10000.0f)));
			}
		}
		active = true;
	}
	
	// Called every frame: Updates the sprite positions for drawing
	public void update() {
		// Draw Update
		for(int count=0; count<numSprites; count++){
			spriteDirOffset[count] += spriteDelDir[count];
			spriteRots[count]+= spriteRotSpeed[count];
		}
	}
	
	// Sets any colliding Wormholes to invalid unless mouse within self
	public void collision(Item other) {
		if (other instanceof Wormhole){
			Wormhole cOther = (Wormhole)other;
			if(cOther.x != this.x & cOther.y != this.y & Math.sqrt(Math.pow(cOther.x2-this.x,2)+Math.pow(cOther.y2-this.y,2)) > r){ // if the starting end of the wormhole is not connected
				cOther.setPlacementValidity(false);		 																			// to this planet
			}
		}
	}
	
	// Called when destroyed: removes self from AsteroidField list
	public void destroy() {
		idList.remove(this); // Needed for collision checking
	}
	
	// Called every frame: Draws the sprites making up the AsteroidField and resource rate
	public void draw() {
		Graphics2D gh = Game.getGraphicsHandle();
		//sprite.draw(gh, x, y,0, scale);
		for(int count=0; count<numSprites; count++){
			int tmpX = (int) (spriteDisOffset[count]*Math.cos(spriteDirOffset[count]));
			int tmpY = (int) (spriteDisOffset[count]*Math.sin(spriteDirOffset[count]));
			sprite.draw(gh, x+tmpX, y+tmpY, spriteRots[count], spriteScales[count]);
		}
		
		// Draw resource rate
		String rateTxtHeader = "Ore Rate:";
		String rateTxt = String.format("%.3g%n/s", orePushRate);
		gh.setFont(new Font("Serif", Font.PLAIN, 20));
		FontRenderContext frc = gh.getFontRenderContext();
		Rectangle2D rect = gh.getFont().getStringBounds(rateTxt, frc);
		Rectangle2D rectHeader = gh.getFont().getStringBounds(rateTxtHeader, frc);
		int xPosHeader = (int) (x - rectHeader.getWidth()/2);
		int yPosHeader = (int) (y);
		int xPos = (int) (x - rect.getWidth()/2);
		int yPos = (int) (y + rectHeader.getHeight());
		gh.setColor(new Color(0.0f,0.0f,0.0f,0.60f));
		int textWidth = (int) Math.max(rect.getWidth(), rectHeader.getWidth());
		gh.fillRoundRect(x-(int)(textWidth/2) - 3, yPosHeader - 3 - (int)rectHeader.getHeight(), (int)textWidth+6, (int)rect.getHeight()+(int)rectHeader.getHeight()+6, 8, 8);
		gh.setColor(Color.WHITE);
		gh.drawChars(rateTxt.toCharArray(), 0, rateTxt.length(), xPos, yPos-3);
		gh.drawChars(rateTxtHeader.toCharArray(), 0, rateTxtHeader.length(), xPosHeader, yPosHeader-3);
	}
	
	// Function needed in each item class for collision checking
	public static int checkCollision(Item other, Boolean notify) {
		int num = 0;
		for (int i = 0; i < idList.size(); i++) {
			Item idOn = (Item)idList.get(i);
			if (idOn != other) {
				if (Item.intersection(other, idOn)) {
					if (notify) {
						idOn.collision(other);
					}
					num++;
				}
			}
		}
		return num;
	}
	
	// Returns the Item on the other end of the Wormhole currently being constructed if AsteroidField
	public static Item getWormholeEnd(){
		Item returnItem = null;
		for(int count=0;count<idList.size();count++){
			Item tempItem = idList.get(count);
			if (Math.sqrt(Math.pow(tempItem.x-ViewControl.mouseX(),2)+Math.pow(tempItem.y-ViewControl.mouseY(),2)) < tempItem.r){
				returnItem = idList.get(count);
				break;
			}
			
		}
		return returnItem;
	}
	
	// Connects a Wormhole to self and also clears Fog around area
	public void addWormhole(Wormhole wid) {
		if (whList.isEmpty()) {
			Fog.uncover(x, y, 300);
		}
		whList.add(wid);
	}
	
	// Deletes a Wormhole from list
	public void removeWormhole(Wormhole wid){
		for(int count=0; count < whList.size(); count++){
			Wormhole nextHole = (Wormhole)whList.get(count);
			if(nextHole == wid){
				whList.remove(count);
				break;
			}
		}
	}
	
	// Called every second: is used to push ore to connected planets
	public static void secondPulse(){
		for(Iterator it = idList.iterator(); it.hasNext();){
			AsteroidField idOn = (AsteroidField)it.next();
	    	int planetCount = 0;
	    	float oreDistribution = 0;
	    	LinkedList<Planet> planetList = new LinkedList<Planet>();
	    	for(Iterator it2 = idOn.whList.iterator(); it2.hasNext();){
	    		Wormhole tempWormhole = (Wormhole)it2.next();
	    		Planet tempPlanet = tempWormhole.getOtherPlanet(idOn);
	    		if(tempPlanet == null){
	    			continue;
	    		}
	    		if(tempPlanet.maxOre > tempPlanet.ore && tempWormhole.active){
	    			planetCount++;
	    			planetList.add(tempPlanet);
	    		}
	    	}
	    	if(planetCount > 0){
    			oreDistribution = idOn.orePushRate/(float)planetCount;
    			Boolean allDistributed = false;
    			Boolean allFull = false;
    			float oreLeft = idOn.orePushRate;
    			while(!allDistributed && !allFull){
    				allFull = true;
    				allDistributed = true;
	    			for(Iterator it3 = planetList.iterator(); it3.hasNext();){
	    				Planet pushPlanet = (Planet)it3.next();
	    				if(oreLeft == 0){
	    					break;
	    				}
	    				else if(pushPlanet.ore + oreDistribution <= pushPlanet.maxOre){
	    					pushPlanet.ore += oreDistribution;
	    					oreLeft -= oreDistribution;
	    					allFull = false;
	    					allDistributed = false;
	    				}
	    				else if(pushPlanet.ore == pushPlanet.maxOre){
	    					continue;
	    				}
	    				else if(pushPlanet.ore + oreDistribution > pushPlanet.maxOre){
	    					float tempOre = pushPlanet.maxOre - pushPlanet.ore;
	    					pushPlanet.ore = pushPlanet.maxOre;
	    					oreLeft -= tempOre;
	    					allFull = false;
	    					allDistributed = false;
	    				}
	    				if(oreLeft <= 0){
	    					allDistributed = true;
	    				}
	    			}
    			}
    		}
		}
	}

}
